/**
 * 
 * @author  樊少冰
 * @description  CSV 文件解析器(整体读取)
 */

#include "CsvLoader.h"

#define MAX_LINE_SIZE 67108864


CsvLoader::CsvLoader(char* path)
{
	this->input = fopen(path, "rb");
	if (this->input == NULL) {
		throw "File not found";
	}
	fseek(this->input, 0, SEEK_END);
	this->file_size = ftell(this->input);
	fseek(this->input, 0, SEEK_SET);

	this->buffer = new uint8_t[this->file_size + 64];
	if (this->buffer == NULL) {
		throw "File too large";
	}
	fread(this->buffer, this->file_size, 1, this->input);
	this->buffer[this->file_size] = '\0';

	this->position = 0;
	this->lastIsCr = false;

	this->row_buffer = new uint8_t[MAX_LINE_SIZE + 64];
	this->row_index = 0;
}


CsvLoader::~CsvLoader()
{
	fclose(this->input);
	delete this->buffer;
	delete this->row_buffer;
}


Slice CsvLoader::read_line()
{
	uint32_t start = this->position;
	uint32_t length = 0;
	int byte;
	while (true) {
		if (this->position >= this->file_size)
			return { 0, 0 };

		byte = this->buffer[this->position];
		this->position += 1;

		if (byte == '\n') {
			if (this->lastIsCr) {
				start += 1;
				continue;
			}
			break;
		}
		else if (byte == '\r') {
			this->lastIsCr = true;
			break;
		}
		length += 1;
	}
	return { start, length };
}


void CsvLoader::write_row_buffer(uint8_t ch) {
	this->row_buffer[this->row_index] = ch;
	this->row_index += 1;
}


size_t CsvLoader::size()
{
	return this->file_size;
}


std::vector<char*>* CsvLoader::read_row()
{
	std::vector<char*>* row = new std::vector<char*>();

	Slice line = this->read_line();
	if (line.length == 0) {
		delete row;
		return NULL;
	} else {
		this->row_index = 0;
		char* fieldValue = (char*)this->row_buffer;
		char* str_line = (char*) & this->buffer[line.start];
		int mode = 0;
		bool lastIsQ = false;

		int i = 0;
		while (i < line.length) {
			char ch = str_line[i];
			if (mode == 0) {
				// 外面
				if (ch == ',') {
					// 当前词结束
					this->write_row_buffer('\0');
					row->push_back(fieldValue);
					fieldValue = (char*)(&this->row_buffer[this->row_index]);
				}
				else if (ch == '\"') {
					mode = 1;
				}
				else {
					this->write_row_buffer(ch);
				}
			}
			else if (mode == 1) {
				// 引号中
				if (ch == '\"') {
					if (i + 1 < line.length && str_line[i + 1] == '\"') {
						// 连续双引号
						i += 1;
						this->write_row_buffer('\"');
					}
					else {
						// 退出双引号
						mode = 0;
					}
				}
				else {
					this->write_row_buffer(ch);
				}
			}

			i += 1;
		}

		// 最后一个词结束
		this->write_row_buffer('\0');
		row->push_back(fieldValue);
	}

	return row;
}
